package com.jiangxjsy.authorization.support;

import com.jiangxjsy.authorization.property.JwtProperty;
import com.jiangxjsy.core.exception.BasicException;
import com.jiangxjsy.core.jwt.JwtCore;
import com.jiangxjsy.core.redis.Redis;
import com.jiangxjsy.core.wrap.ResultCode;
import com.jiangxjsy.model.core.entity.UserInfo;
import com.jiangxjsy.model.core.entity.UserMeta;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.Arrays;
import java.util.List;

/**
 * wukong-crm-master
 * 蒋胜宇
 * 2025/6/4 21:10
 */

@Component
public class PermissionSupport {
    @Resource
    private JwtProperty jwtProperty;

    @Resource
    private Redis redis;

    /**
     * 基于 jwt token 严格获取用户元信息，包含 redis 缓存验证
     * 一般用于网关 token 模式使用 jwt-uuid 模式，且在网关中没有续签 redis 缓存
     *
     * @param authentication 用户权限标识
     * @return UserMeta
     */
    public UserMeta jwtTokenUserMetaStrict(String authentication) {
        UserMeta userMeta;
        try {
            userMeta = new JwtCore<>(UserMeta.class).analyzeToken(authentication, jwtProperty.getPublicKey());
        } catch (Exception ignore) {
            throw new BasicException(ResultCode.SystemResultCode.SYSTEM_NOT_LOGIN);
        }
        if (!redis.hasKey(authentication)) {
            throw new BasicException(ResultCode.SystemResultCode.SYSTEM_NOT_LOGIN);
        }
        return userMeta;
    }

    /**
     * 基于 jwt token 简易获取用户元信息，没有 redis 缓存验证
     * 除非明确知道 redis 缓存存在，才使用此方法
     * 比如在网关中对所有携带 token 的有效请求续签 token 在 redis 中的缓存
     * 或者网关 token 模式使用 jwt 模式
     *
     * @param authentication 用户权限标识
     * @return UserMeta
     */
    public UserMeta jwtTokenUserMetaSimple(String authentication) {
        try {
            return new JwtCore<>(UserMeta.class).analyzeToken(authentication, jwtProperty.getPublicKey());
        } catch (Exception ignore) {
            throw new BasicException(ResultCode.SystemResultCode.SYSTEM_NOT_LOGIN);
        }
    }

    /**
     * 基于任意模式的 token 获取用户信息
     *
     * @param authentication 用户权限标识
     * @return UserInfo
     */
    public UserInfo anyTokenUserInfo(String authentication) {
        UserInfo userInfo = redis.get(UserInfo.class, authentication);
        if (userInfo == null) {
            throw new BasicException(ResultCode.SystemResultCode.SYSTEM_NOT_LOGIN);
        }
        return userInfo;
    }

    /**
     * 判断是否有权限
     *
     * @param noAuthMenuUrls 无权限菜单
     * @param url 请求地址
     * @return 存在与否
     */
    public boolean isHasPermission(List<String> noAuthMenuUrls, String url) {
        // 用户信息丢失
        if (noAuthMenuUrls == null) {
            return false;
        }

        // 管理员
        if (noAuthMenuUrls.isEmpty()) {
            return true;
        }

        //没有任何权限
        if (noAuthMenuUrls.size() == 1 && "/*/**".equals(noAuthMenuUrls.get(0))) {
            return false;
        }

        boolean permission = true;
        for (String noAuthMenuUrl : noAuthMenuUrls) {
            if (noAuthMenuUrl.contains("*")) {
                if (noAuthMenuUrl.contains(",")) {
                    boolean isNoAuth = false;
                    for (String noAuthUrl : noAuthMenuUrl.split(",")) {
                        if (url.startsWith(noAuthUrl.replace("*", ""))) {
                            isNoAuth = true;
                            break;
                        }
                    }
                    if (isNoAuth) {
                        permission = false;
                        break;
                    }
                } else {
                    if (url.startsWith(noAuthMenuUrl.replace("*", ""))) {
                        permission = false;
                        break;
                    }
                }
            } else {
                if (noAuthMenuUrl.contains(",")) {
                    if (Arrays.asList(noAuthMenuUrl.split(",")).contains(url)) {
                        permission = false;
                        break;
                    }
                } else {
                    if (noAuthMenuUrl.equals(url)) {
                        permission = false;
                        break;
                    }
                }
            }
        }
        return permission;
    }
}
